Mule : Writing Mule Transport Providers
This page last changed on Jun 02, 2006 by stephen fenech.
Transport providers are used to provide connectivity to an underlying data source or message source in a consistent way.
In a NutshellA transport provider consists of a set of interface implementations that expose the features for the underlying transport. Cannot resolve external resource into attachment.
Transport Provider InterfacesThere are set of interfaces that need to be implemented when writing a transport provider for Mule. These interfaces define the contract between Mule and the underlying technology. org.mule.umo.UMOConnectorThe connector is used by Mule to register listeners and create message dispatchers for the transport. Configuration parameters that should be shared by all Message Receivers and Dispatchers are stored on the connector. Usually, only one connector instance is needed for multiple inbound and outbound endpoints as multiple Message Receivers and Dispatchers can be associated with a connector. However, where the underlying transport API has the notion of a Connection such as the Jms or Jdbc API there should be a one to one mapping between Mule Connector and the underlying connection. org.mule.umo.UMOMessageReceiverThe Message Receiver is used to receive incoming data from the underlying transport and package it up as an event. The Message Receiver is essentially the server implementation of the transport (where the Message Dispatcher is a client implementation). For example, the Http Message Receiver is a Http server implementation that accepts http requests. An implementation of this class is needed if the transport supports inbound communication. org.mule.umo.UMOMessageDispatcherThe Message Dispatcher is used to send events, which is akin to making client calls with the underlying technology. For example the Axis Message Dispatcher will make a web service call. An implementation of this class is needed if the transport supports outbound communication. org.mule.umo.UMOMessageDispatcherFactoryThis is a factory class used to create UMOMessageDispatcher instances. An implementation of this class is needed if the transport supports outbound communication. org.mule.umo.UMOMessageAdapterThe message adapter is used to provide a consistent way of reading messages in Mule. The massage adapter provides methods for reading the payload of the message and reading message properties. These properties may be message headers, custom properties or other meta information about the message. ImplementationWhere do I start?Mule provides abstract implementations for all of the above interfaces. These implementations handle all the Mule specifics leaving a few abstract methods where custom transport code should be implemented. So writing a custom transport provider is as easy as writing/embedding client and or server code specific to the underlying technology. The following sections describes the implementations available to you. ConnectorsThe org.mule.providers.AbstractConnector implements all the default functionality required for Mule connectors, such as threading configuration, and receiver/dispatcher management. Details about the standard connector properties can be found here. Further properties can be set on the connector depending on the implementation. Often a connector will have a set of properties that can be overridden on a per endpoint basis, meaning the properties set on the connector serve as defaults when an endpoint configuration doesn't provide overrides. Sometimes connector is responsible for managing a connection resource of the transport where the underlying technology has the notion of a Connection, such as in Jms or Jdbc. These types of connector will have a one to one mapping between a Mule connector and the underlying connection. So if you want to have two or more physical Jms connections in a single Mule instance a new connector should be created for each connection. Methods to Implement
Message ReceiversMessage Receivers will behave a bit differently for each transport, but Mule provides some standard implementations that can be used for polling resources and managing transactions for the resource. Usually there are 2 types of Message Receiver; Polling and Listener-based.
The abstract implementations provided by Mule are described below. AbstractMessageReceiverThe AbstractMessageReceiver provides methods for routing events. Developers extending this class should set up the necessary code to register the object as a listener to the transport. This will usually be a case of implementing a listener interface and registering itself . Methods to Implement
PollingMessageReceiverIts quite common for some transport providers to poll a resource periodically waiting for new data to arrive. The PollingMessageRecievers implements the code necessary to setup and destroy a listening thread and provides single method poll() that is invoked repeatedly at a given frequency. Methods to Implement
TransactedMessageReceiverThe TransactedMessageReceiver can be used by transaction-enabled transports to manage transactions for incoming requests. This receiver uses a transaction template to execute requests in transactions and the transactions themselves are created according to the endpoint configuration for the receiver. Methods to Implement
Connection StrategyConnection Strategy classes can be used to customise the way a connection is made to the transport when the connection fails or the Mule connector is started. Connection strategies are responsible for controlling how and when the doConnect() method is called on the UMOMessageReceiver and can provide fault tolerance when endpoints unexpectedly disconnect. For example a strategy may be to try and reconnect 4 times at 5 second intervals. Connection strategies can be configured on each connector independently or a global strategy can be set on the MuleConfiguration object (which is configured in Xml using the <mule-environment-properties> element). Custom connection strategies must implement org.mule.providers.ConnectionStrategy. There is an AbstractConnectionStrategy that has support for executing the connection in a separate thread in case of a long-running strategy. Thread ManagementIt's common for receivers to spawn a thread per request. All receiver threads are allocated using the WorkManager on the receiver. The WorkManager is responsible for executing units of work in a thread. It has a thread pool that allows threads to be reused and ensures that only a prescribed number of threads will be spawned. The WorkManager is an implementation of UMOWorkManager which really just a wrapper of javax.resource.spi.work.WorkManager with some extra lifecycle methods. There is a getWorkManager() method on the AbstractMessageReceiver that can be used to get reference to the WorkMAnager for the receiver. Work items (i.e. the code to execute in a separate thread) must implement javax.resource.spi.work.Work. This extends java.lang.Runnable and thus has a run() method which will be invoked by the WorkManager. When scheduling work with the WorkManager it is recommended that Developers call scheduleWork(...) on the WorkManager rather than startWork(...). Message DispatchersMessages Receivers are equivalent to a server for the transport in that it will serve up client requests. Whereas, Message Dispatchers are the client implementation of the transport. They are responsible for making client requests over the transport, such as writing to a socket or invoking a web service. The AbstractMessageDispater provides a good base implementation leaving 3 methods for the custom MessageDispatcher to implement. Methods to Implement
Threads and Dispatcher CachingCustom transports do not need to worry about dispatcher threading. Unless threading is turned off, the Dispatcher methods listed above will be executed in their own thread. This is managed by the AbstractMessageDispatcher. When a request is made for a dispatcher, it is looked up from a dispatcher cache on the AbstractConnector. The cache is keyed by the endpoint being dispatched to. If a Dispatcher is not found one is created using the MessageDispatcherFactory and then stored in the cache for later. If developers want a new Dispatcher to be created for each request they can set the disposeDispatcherOnCompletion property on the AbstractConnector to true. This will essentially turn off dispatcher caching. Message AdaptersMessageAdapters are usually simple objects that provide a uniform way of accessing an event payload and associated metadata from a format used by the underlying transport. Almost all messaging protocols have the notion of message payload and header properties, which means that a MessageAdapter just needs to allow access to the header properties using standard Map notation i.e. //Jms message id String id = (String)message.getProperty("JMSMssageID"); or //Http content length int contentLength = message.getIntProperty("Content-Length"); Note that the property names use the same name that is used by the underlying transport; 'Content-Length' is a standard Http header name and JMSMessageID is the equivalent bean property name on the javax.jms.Message interface. Message Adapter should extend the org.mule.provider.AbstractMessageAdapter as this abstract class implements much of the mundane methods needed by the org.mule.providers.UMOMessageAdapter . Methods to Implement
Service DescriptorsA service descriptor is a file that contains a number of properties that describes how the internals of a transport provider is configured i.e. which Dispatcher factory to use or which endpoint builder to use. META-INF/services/org/mule/providers/<protocol> The following describes each of the properties that can be set in a Transport service descriptor.
Coding StandardsPackage StructureAll mule providers have a similar package structure. They follow the convention of - org.mule.providers.<protocol> Where protocol is the protocol identifier of the transport such as 'tcp' or 'soap'. Any transformers and filters for the transport are stored either a 'transformers' or 'filters' package under the main package. Note that where a provider may have more than one implementation for a given protocol i.e. There are two Soap implementations in Mule, Axis and Glue, the package name to be used should be soap not axis or glue. InternationalisationAny exceptions messages used in your transport provider implementation should be stored in a resource bundle so that they can be internationalised . The message bundle is a standard java properties file and must be located at - META-INF/services/org/mule/i18n/<protocol>-message.properties |
Document generated by Confluence on Nov 27, 2006 10:27 |